#ifndef __ANIMATION_H__
#define __ANIMATION_H__

#include <string>
#include <list>
#include <iostream>
#include "Observer.h"
#include "DebugLog.h"

class AnimationFunc
{
public:
	virtual bool operator () () = 0;
	virtual bool operator == ( const AnimationFunc& ) = 0;
	
	// ned to fix this observing thought NCenter
	virtual ~AnimationFunc() 
	{
		
	}
	
};

template< class T, typename AnimValue >
class AnimationFuncDihotomy : public AnimationFunc
{
	typedef void ( T::*Setter )( AnimValue& );
	typedef AnimValue ( T::*Getter )( );

public:
	

public:
	
	AnimationFuncDihotomy( T* object, Setter setter, Getter getter, AnimValue& newValue, AnimValue& eps, float startKoef = 1.0f, float endKoef = 1.0f ) : 
									_object( object ),
									_setter( setter ), 
									_getter( getter ), 
									_newValue( newValue ), 
									_startKoef( startKoef ), 
									_endKoef( endKoef ),
									_eps( eps )
	{
		//DEBUGLOGLN( "---------- AnimationFuncDihotomy constructor " )
		//DEBUGLOGLN( " start Anim with value = " ) DEBUGLOG( ( _object->*_getter )() )
		//DEBUGLOGLN( " new Anim value = " ) DEBUGLOG( newValue )
	}
	
	~AnimationFuncDihotomy()
	{
		// need to fix throught NCenter
		//DEBUGLOGLN( std::wstring( TEXT( "---------- AnimationFuncDihotomy destructor " ) ) )

		IParam* animObject = new Param< T >( *_object );
		if ( abs( ( _object->*_getter )() - _newValue ) > _eps )
		{
			//DEBUGLOGLN( " stoped Anim with value = " ) DEBUGLOG( ( _object->*_getter )() )
			( *observer )( animObject );
			//Application::_()->nCenter->post( Animation::didStopAnimation, animObject );
		}
		else
		{
			//DEBUGLOGLN( " ended Anim with value = " ) DEBUGLOG( ( _object->*_getter )() )
			( *observer )( animObject );
			//Application::_()->nCenter->post( Animation::didEndAnimation, animObject );
		}
		delete animObject;
		delete observer;
	}
	
	virtual bool operator() ()
	{
		bool result = false;

		AnimValue tmpValue = ( _object->*_getter )();

		if ( abs( tmpValue - _newValue ) > _eps )
		{
			tmpValue = ( _newValue * _endKoef + tmpValue * _startKoef ) / ( _endKoef + _startKoef );
			( _object->*_setter )( tmpValue );
		}
		else
		{
			( _object->*_setter )( _newValue );
			result = true;
		}
	
		return result;
	}

	virtual bool operator == ( const AnimationFunc& animFunc )
	{
		AnimationFuncDihotomy< T, AnimValue >* animDih = dynamic_cast< AnimationFuncDihotomy< T, AnimValue >* >( const_cast< AnimationFunc* >( &animFunc ) );
		return ( _object == animDih->_object && _setter == animDih->_setter && _getter == animDih->_getter );
	}

	void setStartKoef( float startKoef )
	{
		_startKoef = startKoef;
	}

	void setEndKoef( float endKoef )
	{
		_endKoef = endKoef;
	}

	IObserver*	observer;
private:

	T*		_object;
	Setter	_setter;
	Getter	_getter;

	AnimValue	_newValue;
	AnimValue	_eps;

	float		_startKoef;
	float		_endKoef;
};

class Animation
{
public:
							~Animation( );

	void					addAnimation( AnimationFunc* func );
	void					removeAnimation( AnimationFunc* func );
	//void					removeAnimation( std::wstring name );

	void					removeAllAnimations();

	// true if no more animations 
	bool					operator () ();

	static Animation*		_();

	static const std::wstring didEndAnimation;
	static const std::wstring didStopAnimation;
private:
	static Animation*		__;
							Animation( );
							Animation( const Animation& animation );
	Animation&				operator = ( const Animation& animation );
private:
	std::list< AnimationFunc* >		_animations;
};

#endif